package com.stragegy.service.payment;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.stragegy.enums.PaymentTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * @author xychen
 * @date 2022/10/18
 * @description: 策略工厂
 */
@Service
@Slf4j
public class PaymentStrategyFactory {

    /**
     * 保存策略列表
     */
    private final List<PaymentStrategy> strategyList;

    /**
     * key 为业务来源, value 为对应数据存储策略
     */
    private static final ConcurrentMap<String, PaymentStrategy> STRATEGY_MAP = new ConcurrentHashMap<>();

    public PaymentStrategyFactory(List<PaymentStrategy> strategyList) {
        this.strategyList = strategyList;
        initStrategy();
    }


    /**
     * 根据保存策略列表 初始化策略 Map
     */
    private void initStrategy() {
        if (CollectionUtil.isEmpty(strategyList)) {
            return;
        }

        for (PaymentStrategy strategy : strategyList) {
            for (PaymentTypeEnum value : PaymentTypeEnum.values()) {
                if (strategy.matchBizSource(value)) {
                    PaymentStrategy existsStrategy = STRATEGY_MAP.get(value.getCode());
                    // 多个策略对应同一个业务了
                    if (existsStrategy != null) {
                        String errMsg = StrUtil.format("multi strategy for bizSource: {}, strategy1: {}, strategy2: {}", value.getCode(), existsStrategy, strategy);
                        log.error(errMsg);
                        throw new IllegalArgumentException(errMsg);
                    }

                    // 存储映射
                    STRATEGY_MAP.put(value.getCode(), strategy);
                }
            }
        }
    }

    /**
     * 根据业务来源枚举获取对应存储策略
     *
     * @param businessTypeEnum 业务来源
     * @return 存储策略
     */
    public static PaymentStrategy getStrategy(PaymentTypeEnum businessTypeEnum) {
        return STRATEGY_MAP.get(businessTypeEnum.getCode());
    }
}
